home *** CD-ROM | disk | FTP | other *** search
/ Sun Solutions 1997 April to September / Sun Solutions CD - APR '97 - SEP '97 (704-3778-12 Rev. H)(Sun Microsystems, Inc.)(1997).iso / products / Hyperion / src / plat_linux.c < prev    next >
C/C++ Source or Header  |  1997-02-26  |  9KB  |  483 lines

  1. /*
  2.  * @(#)plat_linux.c    1.8    5/14/94
  3.  *
  4.  * Linux-specific drive control routines.  Very similar to the Sun module.
  5.  */
  6. static char *ident = "@(#)plat_linux.c    1.8 5/14/94";
  7.  
  8. #ifdef linux
  9.  
  10. #include <errno.h>
  11. #include <stdio.h>
  12. #include <sys/types.h>
  13. #include <fcntl.h>
  14. #include <sys/param.h>
  15. #include <sys/stat.h>
  16. #include <sys/time.h>
  17. #include <linux/cdrom.h>
  18.  
  19. #include "struct.h"
  20.  
  21. #define DEFAULT_CD_DEVICE    "/dev/sr0"
  22.  
  23. #define max(a,b) ((a) > (b) ? (a) : (b))
  24.  
  25. #ifdef LINUX_SCSI_PASSTHROUGH
  26. # define SCSI_IOCTL_SEND_COMMAND 1
  27. #endif
  28.  
  29. void *malloc();
  30. char *strchr();
  31.  
  32. int    min_volume = 128;
  33. int    max_volume = 255;
  34.  
  35. extern char    *cd_device;
  36.  
  37. /*
  38.  * Initialize the drive.  A no-op for the generic driver.
  39.  */
  40. int
  41. gen_init(d)
  42.     struct wm_drive    *d;
  43. {
  44.     return (0);
  45. }
  46.  
  47. /*
  48.  * Get the number of tracks on the CD.
  49.  */
  50. int
  51. gen_get_trackcount(d, tracks)
  52.     struct wm_drive    *d;
  53.     int        *tracks;
  54. {
  55.     struct cdrom_tochdr    hdr;
  56.  
  57.     if (ioctl(d->fd, CDROMREADTOCHDR, &hdr))
  58.         return (-1);
  59.     
  60.     *tracks = hdr.cdth_trk1;
  61.     return (0);
  62. }
  63.  
  64. /*
  65.  * Get the start time and mode (data or audio) of a track.
  66.  */
  67. int
  68. gen_get_trackinfo(d, track, data, startframe)
  69.     struct wm_drive    *d;
  70.     int        track, *data, *startframe;
  71. {
  72.     struct cdrom_tocentry    entry;
  73.  
  74.     entry.cdte_track = track;
  75.     entry.cdte_format = CDROM_MSF;
  76.  
  77.     if (ioctl(d->fd, CDROMREADTOCENTRY, &entry))
  78.         return (-1);
  79.     
  80.     *startframe =    entry.cdte_addr.msf.minute * 60 * 75 +
  81.             entry.cdte_addr.msf.second * 75 +
  82.             entry.cdte_addr.msf.frame;
  83.     *data = entry.cdte_ctrl & CDROM_DATA_TRACK ? 1 : 0;
  84.     
  85.     return (0);
  86. }
  87.  
  88. /*
  89.  * Get the number of frames on the CD.
  90.  */
  91. int
  92. gen_get_cdlen(d, frames)
  93.     struct wm_drive    *d;
  94.     int        *frames;
  95. {
  96.     int        tmp;
  97.  
  98.     return (gen_get_trackinfo(d, CDROM_LEADOUT, &tmp, frames));
  99. }
  100.  
  101.  
  102. /* Alarm signal handler. */
  103. static void do_nothing(x) int x; { x++; }
  104.  
  105. /*
  106.  * Get the current status of the drive: the current play mode, the absolute
  107.  * position from start of disc (in frames), and the current track and index
  108.  * numbers if the CD is playing or paused.
  109.  */
  110. int
  111. gen_get_drive_status(d, oldmode, mode, pos, track, index)
  112.     struct wm_drive    *d;
  113.     enum cd_modes    oldmode, *mode;
  114.     int        *pos, *track, *index;
  115. {
  116.     struct cdrom_subchnl        sc;
  117.     struct itimerval        old_timer, new_timer;
  118.  
  119.     /* If we can't get status, the CD is ejected, so default to that. */
  120.     *mode = EJECTED;
  121.  
  122.     /* Is the device open? */
  123.     if (d->fd < 0)
  124.     {
  125.         switch (wmcd_open(d)) {
  126.         case -1:    /* error */
  127.             return (-1);
  128.  
  129.         case 1:        /* retry */
  130.             return (0);
  131.         }
  132.     }
  133.  
  134.     sc.cdsc_format = CDROM_MSF;
  135.  
  136.     if (ioctl(d->fd, CDROMSUBCHNL, &sc))
  137.         return (0);
  138.  
  139.     switch (sc.cdsc_audiostatus) {
  140.     case CDROM_AUDIO_PLAY:
  141.         *mode = PLAYING;
  142.         *track = sc.cdsc_trk;
  143.         *index = sc.cdsc_ind;
  144.         *pos = sc.cdsc_absaddr.msf.minute * 60 * 75 +
  145.             sc.cdsc_absaddr.msf.second * 75 +
  146.             sc.cdsc_absaddr.msf.frame;
  147.         break;
  148.  
  149.     case CDROM_AUDIO_PAUSED:
  150.     case CDROM_AUDIO_NO_STATUS:
  151.     case CDROM_AUDIO_INVALID: /**/
  152.         if (oldmode == PLAYING || oldmode == PAUSED)
  153.         {
  154.             *mode = PAUSED;
  155.             *track = sc.cdsc_trk;
  156.             *index = sc.cdsc_ind;
  157.             *pos = sc.cdsc_absaddr.msf.minute * 60 * 75 +
  158.                 sc.cdsc_absaddr.msf.second * 75 +
  159.                 sc.cdsc_absaddr.msf.frame;
  160.         }
  161.         else
  162.             *mode = STOPPED;
  163.         break;
  164.  
  165.     case CDROM_AUDIO_COMPLETED:
  166.         *mode = TRACK_DONE; /* waiting for next track. */
  167.         break;
  168.  
  169.     default:
  170.         *mode = UNKNOWN;
  171.         break;
  172.     }
  173.  
  174.     return (0);
  175. }
  176.  
  177. /*
  178.  * scale_volume(vol, max)
  179.  *
  180.  * Return a volume value suitable for passing to the CD-ROM drive.  "vol"
  181.  * is a volume slider setting; "max" is the slider's maximum value.
  182.  *
  183.  * On Sun and DEC CD-ROM drives, the amount of sound coming out the jack
  184.  * increases much faster toward the top end of the volume scale than it
  185.  * does at the bottom.  To make up for this, we make the volume scale look
  186.  * sort of logarithmic (actually an upside-down inverse square curve) so
  187.  * that the volume value passed to the drive changes less and less as you
  188.  * approach the maximum slider setting.  The actual formula looks like
  189.  *
  190.  *     (max^2 - (max - vol)^2) * (max_volume - min_volume)
  191.  * v = --------------------------------------------------- + min_volume
  192.  *                           max^2
  193.  *
  194.  * If your system's volume settings aren't broken in this way, something
  195.  * like the following should work:
  196.  *
  197.  *    return ((vol * (max_volume - min_volume)) / max + min_volume);
  198.  */
  199. static int
  200. scale_volume(vol, max)
  201.     int    vol, max;
  202. {
  203.     return ((max * max - (max - vol) * (max - vol)) *
  204.         (max_volume - min_volume) / (max * max) + min_volume);
  205. }
  206.  
  207. /*
  208.  * Set the volume level for the left and right channels.  Their values
  209.  * range from 0 to 100.
  210.  */
  211. int
  212. gen_set_volume(d, left, right)
  213.     struct wm_drive    *d;
  214.     int        left, right;
  215. {
  216.     struct cdrom_volctrl v;
  217.  
  218. /* Adjust the volume to make up for the CD-ROM drive's weirdness. */
  219.     left = scale_volume(left, 100);
  220.     right = scale_volume(right, 100);
  221.  
  222.     v.channel0 = v.channel2 = left < 0 ? 0 : left > 255 ? 255 : left;
  223.     v.channel1 = v.channel3 = right < 0 ? 0 : right > 255 ? 255 : right;
  224.  
  225.     return (ioctl(d->fd, CDROMVOLCTRL, &v));
  226. }
  227.  
  228. /*
  229.  * Pause the CD.
  230.  */
  231. int
  232. gen_pause(d)
  233.     struct wm_drive    *d;
  234. {
  235.     return (ioctl(d->fd, CDROMPAUSE));
  236. }
  237.  
  238. /*
  239.  * Resume playing the CD (assuming it was paused.)
  240.  */
  241. int
  242. gen_resume(d)
  243.     struct wm_drive    *d;
  244. {
  245.     return (ioctl(d->fd, CDROMRESUME));
  246. }
  247.  
  248. /*
  249.  * Stop the CD.
  250.  */
  251. int
  252. gen_stop(d)
  253.     struct wm_drive *d;
  254. {
  255.     return (ioctl(d->fd, CDROMSTOP));
  256. }
  257.  
  258. /*
  259.  * Play the CD from one position to another (both in frames.)
  260.  */
  261. int
  262. gen_play(d, start, end)
  263.     struct wm_drive    *d;
  264.     int        start, end;
  265. {
  266.     struct cdrom_msf        msf;
  267.  
  268.     msf.cdmsf_min0 = start / (60*75);
  269.     msf.cdmsf_sec0 = (start % (60*75)) / 75;
  270.     msf.cdmsf_frame0 = start % 75;
  271.     msf.cdmsf_min1 = end / (60*75);
  272.     msf.cdmsf_sec1 = (end % (60*75)) / 75;
  273.     msf.cdmsf_frame1 = end % 75;
  274.  
  275.     if (ioctl(d->fd, CDROMSTART))
  276.         return (-1);
  277.     if (ioctl(d->fd, CDROMPLAYMSF, &msf))
  278.         return (-2);
  279.     
  280.     return (0);
  281. }
  282.  
  283. /*
  284.  * Eject the current CD, if there is one.
  285.  */
  286. int
  287. gen_eject(d)
  288.     struct wm_drive    *d;
  289. {
  290.     struct stat    stbuf;
  291.     struct ustat    ust;
  292.  
  293.     if (fstat(d->fd, &stbuf) != 0)
  294.         return (-2);
  295.  
  296.     /* Is this a mounted filesystem? */
  297.     if (ustat(stbuf.st_rdev, &ust) == 0)
  298.         return (-3);
  299.  
  300.     if (ioctl(d->fd, CDROMEJECT))
  301.         return (-1);
  302.  
  303.     return (0);
  304. }
  305.  
  306. /*
  307.  * Keep the CD open all the time.
  308.  */
  309. void
  310. keep_cd_open()
  311. {
  312.     int    fd;
  313.     struct flock    fl;
  314.     extern    end;
  315.  
  316.     for (fd = 0; fd < 256; fd++)
  317.         close(fd);
  318.  
  319.     if (fork())
  320.         exit(0);
  321.  
  322.     if ((fd = open("/tmp/cd.lock", O_RDWR | O_CREAT, 0666)) < 0)
  323.         exit(0);
  324.     fl.l_type = F_WRLCK;
  325.     fl.l_whence = 0;
  326.     fl.l_start = 0;
  327.     fl.l_len = 0;
  328.     if (fcntl(fd, F_SETLK, &fl) < 0)
  329.         exit(0);
  330.  
  331.     if (open(cd_device, 0) >= 0)
  332.     {
  333.         brk(&end);
  334.         pause();
  335.     }
  336.  
  337.     exit(0);
  338. }
  339.  
  340. /*
  341.  * Read the initial volume from the drive, if available.  Each channel
  342.  * ranges from 0 to 100, with -1 indicating data not available.
  343.  */
  344. int
  345. gen_get_volume(d, left, right)
  346.     struct wm_drive    *d;
  347.     int        *left, *right;
  348. {
  349.     /* Suns, HPs, Linux, NEWS can't read the volume; oh well */
  350.     *left = *right = -1;
  351.  
  352.     return (0);
  353. }
  354.  
  355. /*
  356.  * Send an arbitrary SCSI command to a device.
  357.  */
  358. int
  359. wm_scsi(d, cdb, cdblen, retbuf, retbuflen, getreply)
  360.     struct wm_drive    *d;
  361.     unsigned char    *cdb;
  362.     int        cdblen;
  363.     void        *retbuf;
  364.     int        retbuflen;
  365.     int        getreply;
  366. {
  367. #ifdef LINUX_SCSI_PASSTHROUGH
  368.  
  369.         char *cmd;
  370.     int cmdsize;
  371.  
  372.     cmdsize = 2 * sizeof(int);
  373.     if (retbuf)
  374.       {
  375.         if (getreply) cmdsize += max(cdblen, retbuflen);
  376.         else cmdsize += (cdblen + retbuflen);
  377.       }
  378.     else cmdsize += cdblen;
  379.       
  380.     cmd = malloc(cmdsize);
  381.     if (cmd == NULL)
  382.       return (-1);
  383.  
  384.     ((int*)cmd)[0] = cdblen + ((retbuf && !getreply) ? retbuflen : 0);
  385.     ((int*)cmd)[1] = ((retbuf && getreply) ? retbuflen : 0);
  386.  
  387.     memcpy(cmd + 2*sizeof(int), cdb, cdblen);
  388.     if (retbuf && !getreply)
  389.       memcpy(cmd + 2*sizeof(int) + cdblen, retbuf, retbuflen);
  390.     
  391.     if (ioctl(d->fd, SCSI_IOCTL_SEND_COMMAND, cmd))
  392.       {
  393.         free(cmd);
  394.         return (-1);
  395.       }
  396.     
  397.     if (retbuf && getreply)
  398.       memcpy(retbuf, cmd + 2*sizeof(int), retbuflen);
  399.  
  400.     free(cmd);
  401.     return 0;
  402.  
  403. #else
  404.     return (-1);
  405. #endif
  406. }
  407.  
  408. /*
  409.  * Open the CD device and figure out what kind of drive is attached.
  410.  */
  411. int
  412. wmcd_open(d)
  413.     struct wm_drive    *d;
  414. {
  415.     int        fd;
  416.     static int    warned = 0;
  417.  
  418. #ifdef LINUX_SCSI_PASSTHROUGH
  419.     char vendor[9], model[17], rev[5];
  420. #endif
  421.  
  422.     if (cd_device == NULL)
  423.         cd_device = DEFAULT_CD_DEVICE;
  424.  
  425.     if (d->fd >= 0)        /* Device already open? */
  426.         return (0);
  427.     
  428.     d->fd = open(cd_device, 0);
  429.     if (d->fd < 0)
  430.     {
  431.         if (errno == EACCES)
  432.         {
  433.             if (!warned)
  434.             {
  435.                 fprintf(stderr,
  436.         "As root, please run\n\nchmod 666 %s\n\n%s\n", cd_device,
  437.         "to give yourself permission to access the CD-ROM device.");
  438.                 warned++;
  439.             }
  440.         }
  441.         else if (errno != ENXIO)
  442.         {
  443.             perror(cd_device);
  444.             exit(1);
  445.         }
  446.  
  447.         /* No CD in drive. */
  448.         return (1);
  449.     }
  450.  
  451.     if (warned)
  452.     {
  453.         warned = 0;
  454.         fprintf(stderr, "Thank you.\n");
  455.     }
  456.  
  457.     /* Now fill in the relevant parts of the wm_drive structure. */
  458.     fd = d->fd;
  459.  
  460. #ifdef LINUX_SCSI_PASSTHROUGH
  461.   
  462.     /* Can we figure out the drive type? */
  463.     vendor[0] = model[0] = rev[0] = '\0';
  464.     wm_scsi_get_drive_type(d, vendor, model, rev);
  465.  
  466.     *d = *(find_drive_struct(vendor, model, rev));
  467.     about_set_drivetype(d->vendor, d->model, rev);
  468.  
  469. #else
  470.  
  471.     *d = *(find_drive_struct("", "", ""));
  472.  
  473. #endif
  474.  
  475.     d->fd = fd;
  476.  
  477.     (d->init)(d);
  478.  
  479.     return (0);
  480. }
  481.  
  482. #endif /* linux */
  483.